package metamap.proxy.server;

import gov.nih.nlm.nls.metamap.Ev;
import gov.nih.nlm.nls.metamap.MetaMapApi;
import gov.nih.nlm.nls.metamap.MetaMapApiImpl;
import gov.nih.nlm.nls.metamap.PCM;
import gov.nih.nlm.nls.metamap.Result;
import gov.nih.nlm.nls.metamap.Utterance;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import metamap.proxy.server.jaxws.MetamapService;
import metamap.proxy.server.sax.MetamapHandler;

import org.xml.sax.SAXException;

@WebService(targetNamespace = "http://jaxws.server.proxy.metamap/", name = "MetaMap")
public class MetamapServiceImpl implements MetamapService {
	private static String file_separator = System.getProperty("file.separator");

	BlockingQueue<MetaMapApi> metamap = null;
	boolean test = false;
	Process P[];
/**
 * Tries to instaurate one connection for each mmserver running on the local machine,
 * and sets the params for the futures queries (including the semantic types of interests)
 * System will exit with -1 Error Code in case of critical error, like metamap error
 * or a kill signal received
 */
	public MetamapServiceImpl() {
		super();
		System.out.println("Inizio Costruttore server ");
		P = new Process[4];
		metamap = new LinkedBlockingQueue<MetaMapApi>();
		List<String> config = new ArrayList<String>();
		List<String> groups = new LinkedList<String>();
		// config.add("-t");
		// config.add("-r");

		// config.add("150");
		config.add("-t");	
		groups.add("CHEM");
		groups.add("GENE");
		groups.add("PHYS");
		try {
			config.add("-J");
			config.add(getSemTypes(groups));

		} catch (IOException e) {
			System.out
					.println("Errore nell'accesso ai gruppi semantici specificati: filtro disattivato");
		}

		for (int i = 0; i < 4; i++) {
			int port = 8060 + i;
			MetaMapApi api = null;
			try {
				api = new MetaMapApiImpl("127.0.0.1", port);
				api.setOptions(config);
			} catch (Exception e) {
				System.out.println("Error: server metamap non avviati, abort");
				System.exit(-1);
			}
			try {
				metamap.put(api);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.exit(-1);
			}
		}
		test = true;
		System.out.println("Server up");
	}
/*
	public void MetamapServiceImpl_old(String path) {
		// super();
		envir = Runtime.getRuntime();
		metamappath = path;
		processors_number = envir.availableProcessors();
		sem = new Semaphore(processors_number / 2, true);
		try {
			envir.exec(metamappath + System.getProperty("file.separator")
					+ "bin" + file_separator + "skrmedpostctl start ");
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
*/
	/*
	public MetamapServiceImpl() throws InterruptedException {

		this(System.getProperty("user.home")+"/public_mm/");

	}
*/
	/**
	 * This method is called everytime a text needs to be mapped.
	 * it uses the DOM tree provided from the server to extract the
	 * preferred name values
	 * 
	 * @param text The Abstract needed to be mapped <p>
	 * @return The list containing the preferred names of the input provided, or an empty list if the test was null or empty.
	 */
	private List<String> metamapApi(String text) {
		List<String> preferred = new LinkedList<String>();
		if (text == null || text.equals(""))
			return preferred;
		MetaMapApi api;
		try {
			api = metamap.take();
		} catch (InterruptedException e1) {
			System.out.println("Eccezione metamap gestista");
			return metamapApi(text);
		}

		List<Result> results = api.processCitationsFromString(text);
		if (results.size() == 0) {
			try {
				metamap.put(api);
			} catch (InterruptedException e) {

				e.printStackTrace();
			}
			return preferred;
		}
		for (Result t : results) {
			List<Utterance> utterances = null;
			try {
				utterances = t.getUtteranceList();
			} catch (Exception e) {
				e.printStackTrace();
				break;

			}
			for (Utterance utt : utterances) {
				List<PCM> pcms = null;
				try {
					pcms = utt.getPCMList();
				} catch (Exception e) {
					e.printStackTrace();
					break;
				}
				for (PCM pcm : pcms) {
					List<Ev> candidates = null;
					try {
						candidates = pcm.getCandidateList();
					} catch (Exception e) {
						e.printStackTrace();
						break;
					}
					for (Ev candidate : candidates) {
						try {
							preferred.add(candidate.getPreferredName());
							// System.out.println(candidate.getPreferredName());
						} catch (Exception e) {

							e.printStackTrace();
						}
					}
				}
			}

		}
		try {
			metamap.put(api);
		} catch (InterruptedException e) {
			System.out.println("Interrotto, riprovo");
			try {
				metamap.put(api);
			} catch (InterruptedException e1) {
			}
		}
		return preferred;
	}

	/**
	 * Calls the methods needed to compute the preferred names,
	 * this is the only method seen from the grid
	 * @param text The text to get computed
	 * @param groups The semantic groups to be included
	 * @return A list of string, each string is a preferred name
	 */
	@Override
	public List<String> getPreferredNames(
			@WebParam(name = "text", targetNamespace = "") String text,
			@WebParam(name = "groups", targetNamespace = "") List<String> groups) {

		List<String> res = metamapApi(text);
		System.out.println("fine istanza " + res.size() + " risultati");
		return res;

		/*
		 * sem.acquireUninterruptibly();
		 * 
		 * Process p = null; List<String> result =null;
		 * 
		 * FileWriter fw = null; if (text == null || text.equals("")) {
		 * System.out.println("Warning: ricevuto un testo vuoto"); return new
		 * LinkedList<String>(); }
		 * 
		 * try { File input_file = File.createTempFile("abstract", "_temp");
		 * File output_file = File.createTempFile("computed", "_temp"); fw = new
		 * FileWriter(input_file); BufferedWriter bfw = new BufferedWriter(fw);
		 * bfw.write(text); bfw.write(NEW_LINE); bfw.flush(); bfw.close();
		 * fw.close(); String types =getSemTypes(groups);
		 * 
		 * String command = metamappath + System.getProperty("file.separator") +
		 * "bin" +file_separator +
		 * "metamap10  -% format -t -r 650 -J "+types+" " +
		 * input_file.getAbsolutePath()+" " + output_file.getAbsolutePath(); p =
		 * envir.exec(command); p.waitFor(); p.getErrorStream().close();
		 * p.getInputStream().close(); p.getOutputStream().close(); p.destroy();
		 * result = parsePreferred(output_file.getAbsolutePath());
		 * 
		 * } catch (FileNotFoundException e) {
		 * System.out.println("file non trovato"); } catch (IOException e) { //
		 * TODO Auto-generated catch block e.printStackTrace(); } catch
		 * (InterruptedException e) { // TODO Auto-generated catch block
		 * e.printStackTrace(); } finally {
		 * 
		 * sem.release(); System.out.println("Fine istanza, "// +
		 * sem.availablePermits() + "/" //+ processors_number +
		 * " slot disponibili, " + sem.getQueueLength() + "in coda"); }
		 * 
		 * return result;
		 */
	}

	/**
	 * Get the semantic group files from the hard disk, and returns a comma separated
	 * string including all the semantic types
	 * @param groups A list of strings of semantic types
	 * @return a comma separated string that is the concatenation of all the semantic types
	 * included in the groups provided
	 * 
	 * @throws IOException If the groups provided does not exist
	 */
	private String getSemTypes(List<String> groups) throws IOException {
		StringBuffer sb = new StringBuffer();
		for (String s : groups) {
			FileReader fr = new FileReader("sem_types" + file_separator + s
					+ ".txt");
			BufferedReader br = new BufferedReader(fr);
			sb.append(br.readLine());
		}
		sb.deleteCharAt(sb.length() - 1);
		return sb.toString();
	}

	private String getSemTypes2(List<String> groups) throws IOException {
		StringBuffer sb = new StringBuffer();
		for (String s : groups) {
			FileReader fr = new FileReader("sem_types" + file_separator + s
					+ ".txt");
			BufferedReader br = new BufferedReader(fr);
			sb.append(br.readLine().split(","));
		}
		// sb.deleteCharAt(sb.length()-1);
		return sb.toString();
	}
/**
 * Use a sax parser to extract the preferred name from the response
 * @param br
 * @return
 */
	@Deprecated
	private List<String> parsePreferred(String br) {
		SAXParserFactory factory = SAXParserFactory.newInstance();
		SAXParser saxParser = null;
		MetamapHandler saxHandler = new MetamapHandler();
		try {
			factory.setValidating(false);
			factory
					.setFeature(
							"http://apache.org/xml/features/nonvalidating/load-external-dtd",
							false);
			saxParser = factory.newSAXParser();
			saxParser.parse(br, saxHandler);

		} catch (ParserConfigurationException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (SAXException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return saxHandler.getPreferred();

	}

	/*
	 * private LinkedList<String> getPreferredNames(File inputfile) throws
	 * ParserConfigurationException, SAXException, IOException{
	 * DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
	 * DocumentBuilder builder = factory.newDocumentBuilder(); Document doc =
	 * builder.parse(inputfile); Node root = doc.getDocumentElement(); NodeList
	 * nl = root.getChildNodes(); int n1 = nl.getLength(); //for (Node node :
	 * nl) for (int i = 0; i < n1; i++) { if (nl.item(i).getNodeType() ==
	 * Node.ELEMENT_NODE) { if (((Element) nl.item(i)).getNodeName() == "MMO"){
	 * NodeList MMO = nl.item(i).getChildNodes(); for (int j = 0; j <
	 * MMO.getLength(); j++) { if (((Element) MMO.item(j)).getNodeName() ==
	 * "Utterances"); NodeList Utterances = MMO.item(i).getChildNodes(); for(int
	 * h = 0; h< Utterances.getLength();h++){ if (((Element)
	 * Utterances.item(h)).getNodeName() == "Utterance"); NodeList Utterances =
	 * MMO.item(i).getChildNodes(); for (int k =0;k<) } }
	 * 
	 * } int n2 = nl.getLength();
	 * 
	 * candidate
	 * 
	 * 
	 * 
	 * //parseAircrafts(ele); } } return null;
	 * 
	 * }
	 */
}